package cn.sanli.manage.utils;


import cn.sanli.manage.ex.ServiceException;
import cn.sanli.manage.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;

/**
 * 时间工具类
 *
 * @author zk
 */
@Slf4j
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
    public static final String YYYY = "yyyy";

    public static final String YYYY_MM = "yyyy-MM";

    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static final Date START = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, "1970-01-01 08:00:00");

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    public static final String THISWEEK = "thisWeek";
    public static final String THISMONTH = "thisMonth";
    public static final String THISQUARTER = "thisQuarter";
    public static final String THISHALF = "thisHalf";
    public static final String THISYEAR = "thisYear";

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate()
    {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate()
    {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static String getTime()
    {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static String dateTimeNow()
    {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static String dateTimeNow(final String format)
    {
        return parseDateToStr(format, new Date());
    }

    public static String date(final Date date)
    {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static String dateTime(final Date date)
    {
        return parseDateToStr(YYYY_MM_DD_HH_MM_SS, date);
    }


    /**
     * mongo 日期查询isodate
     *
     * @param date 时间对象
     * @return iso时间对象
     */
    public static Date dateToISODate(Date date){
        //T代表后面跟着时间，Z代表UTC统一时间
        SimpleDateFormat format =
                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));
        String isoDate = format.format(date);
        try {
            return format.parse(isoDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }



    public static String parseDateToStr(final String format, final Date date)
    {
        return new SimpleDateFormat(format).format(date);
    }

    public static Date dateTime(final String format, final String ts)
    {
        try
        {
            return new SimpleDateFormat(format).parse(ts);
        }
        catch (ParseException e)
        {
            throw new RuntimeException(e);
        }
    }

    public static Date formatD(String dateStr){
        return formatD(dateStr,  YYYY_MM_DD_HH_MM_SS);
    }

    public static Date formatD(String dateStr ,String format)  {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        Date ret = null ;
        try {
            ret = simpleDateFormat.parse(dateStr) ;
        } catch (ParseException e) {
            //
        }
        return ret;
    }


    /**
     * 日期路径 即年/月/日 如2018/08/08
     *
     * @return string
     */
    public static String datePath()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     *
     * @return string
     */
    public static String dateTime()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     *
     * @param str 日期对象
     * @return string
     */
    public static Date parseDate(Object str)
    {
        if (str == null)
        {
            return null;
        }
        try
        {
            return parseDate(str.toString(), parsePatterns);
        }
        catch (ParseException e)
        {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     *
     * @return date
     */
    public static Date getServerStartDate()
    {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算时间差
     *
     * @param endDate 最后时间
     * @param startTime 开始时间
     * @return 时间差（天/小时/分钟）
     */
    public static String timeDistance(Date endDate, Date startTime)
    {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - startTime.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 增加 LocalDateTime - Date
     *
     * @param temporalAccessor 本地时间
     * @return date时间
     */
    public static Date toDate(LocalDateTime temporalAccessor)
    {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 增加 LocalDate - Date
     *
     * @param temporalAccessor 本地时间
     * @return date时间
     */
    public static Date toDate(LocalDate temporalAccessor)
    {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 获取某天的下午五点
     *
     * @param time date对象
     * @return date当天五点时间
     */
    public static Date createDesignate(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.HOUR_OF_DAY, 17);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 将某天的日期 天数进行增减
     *
     * @param time date对象
     * @param len 增减天数
     * @return date
     */
    public static Date createToDay(Date time, int len) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, len);
        return calendar.getTime();
    }

    /**
     * 获取当前月份开始时间到结束时间
     *
     * @return Date日期
     */
    public static Map<String, Date[]> getStatisticsTime() {
        Calendar calendar = Calendar.getInstance();
        Map<String, Date[]> map = new HashMap<>();
        // 获取年份
        int year = calendar.get(Calendar.YEAR);
        // 获取月份
        int month = calendar.get(Calendar.MONTH) + 1;
        // 获取日
        int day = calendar.get(Calendar.DATE);
        // 获取周天数
        int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;

        // 开始生成年份
        String startTimeOfYear = year-1 + "-12-26 00:00:00";
        String endTimeOfYear = year + "-12-25 23:59:59";
        log.debug("年份开始: {}", startTimeOfYear);
        log.debug("年份结束: {}", endTimeOfYear);
        // 存入map
        map.put(DateUtils.THISYEAR, new Date[]{formatD(startTimeOfYear), formatD(endTimeOfYear)});

        // 开始生成半年
        String startTimeOfHalf, endTimeOfHalf;
        if((month <= 6 && day <=25)||
                (month == 12 && day >= 26) ||
                month <= 5) {
            startTimeOfHalf = year-1 + "-12-26 00:00:00";
            endTimeOfHalf = year + "-06-25 23:59:59";
        } else {
            startTimeOfHalf = year + "-06-26 00:00:00";
            endTimeOfHalf = year + "-12-25 23:59:59";
        }
        log.debug("半年分开始: {}", startTimeOfHalf);
        log.debug("半年分结束: {}", endTimeOfHalf);
        map.put(DateUtils.THISHALF, new Date[]{formatD(startTimeOfHalf), formatD(endTimeOfHalf)});

        // 开始生成本季度
        String startTimeOfQuarter, endTimeOfQuarter;
        if(month <= 3) {
            if(month == 3 && day >= 26) {
                startTimeOfQuarter = year + "-3-26 00:00:00";
                endTimeOfQuarter = year + "-06-25 23:59:59";
            }else {
                startTimeOfQuarter = year-1 + "-12-26 00:00:00";
                endTimeOfQuarter = year + "-03-25 23:59:59";
            }
        } else if(month <= 6) {
            if(month == 6 && day >= 26) {
                startTimeOfQuarter = year + "-6-26 00:00:00";
                endTimeOfQuarter = year + "-09-25 23:59:59";
            }else {
                startTimeOfQuarter = year + "-3-26 00:00:00";
                endTimeOfQuarter = year + "-06-25 23:59:59";
            }
        } else if(month <= 9) {
            if(month == 9 && day >= 26) {
                startTimeOfQuarter = year + "-9-26 00:00:00";
                endTimeOfQuarter = year + "-12-25 23:59:59";
            }else {
                startTimeOfQuarter = year + "-6-26 00:00:00";
                endTimeOfQuarter = year + "-09-25 23:59:59";
            }
        } else if(month <= 12) {
            if(month ==12 && day >= 26) {
                startTimeOfQuarter = year-1 + "-12-26 00:00:00";
                endTimeOfQuarter = year + "-03-25 23:59:59";
            }
            startTimeOfQuarter = year + "-09-26 00:00:00";
            endTimeOfQuarter = year + "-12-25 23:59:59";
        }else {
            throw new ServiceException(ServiceCode.ERROR_BAD_REQUEST, "DateUtils生成当前季度时间出现异常");
        }
        log.debug("季度开始: {}", startTimeOfQuarter);
        log.debug("季度结束: {}", endTimeOfQuarter);
        // 存入map
        map.put(DateUtils.THISQUARTER, new Date[]{formatD(startTimeOfQuarter), formatD(endTimeOfQuarter)});

        // 开始生成月份
        String startTimeOfMonth, endTimeOfMonth;
        int endMonth;
        if ((day < 31 && day >= 26) || day == 31) {
            endMonth = month + 1;
        } else {
            endMonth = month;
            month-=1;
        }
        startTimeOfMonth = year + "-" + month + "-26 00:00:00";
        endTimeOfMonth = year + "-" + endMonth + "-25 23:59:59";
        log.debug("月份开始: {}", startTimeOfMonth);
        log.debug("月份结束: {}", endTimeOfMonth);
        // 存入map
        map.put(DateUtils.THISMONTH, new Date[]{formatD(startTimeOfMonth), formatD(endTimeOfMonth)});

//        // 开始生成本周
//        if(week == 0) {
//            startTimeOfWeek = year + "-" + month + "-" +
//        }

        String startTimeOfWeek, endTimeOfWeek;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        calendar.setFirstDayOfWeek(Calendar.MONDAY);// 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int dayWeek = calendar.get(Calendar.DAY_OF_WEEK);// 获得当前日期是一个星期的第几天
        if(dayWeek==1) {
            dayWeek = 8;
        }
        calendar.add(Calendar.DATE, calendar.getFirstDayOfWeek() - dayWeek);// 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        Date mondayDate = calendar.getTime();
        String weekBegin = sdf.format(mondayDate);

        calendar.add(Calendar.DATE, 4 + calendar.getFirstDayOfWeek());
        Date sundayDate = calendar.getTime();
        String weekEnd = sdf.format(sundayDate);

        startTimeOfWeek = weekBegin+" 00:00:00";
        endTimeOfWeek =weekEnd+" 23:59:59";
        log.debug("周开始: {}", startTimeOfWeek);
        log.debug("周结束: {}", endTimeOfWeek);
        // 存入map
        map.put(DateUtils.THISWEEK, new Date[]{formatD(startTimeOfWeek), formatD(endTimeOfWeek)});



        return map;
    }

    /**
     * 根据年份月份, 获取这个月开始(26号 00:00:00)到结束(25号 23:59:59)
     * @param year 年份
     * @param month 月份
     * @return 这个月开始(26号 00:00:00)到结束(25号 23:59:59)
     */
    public static Date[] getDateOfMonth(int year, int month) {
        String startTime, endTime;
        if(month == 1) {
            startTime = (year-1) + "-12-26 00:00:00";
        } else {
            startTime = year + "-" + (month-1) + "-26 00:00:00";
        }
        endTime = year + "-" + month +  "-25 00:00:00";
        return new Date[]{formatD(startTime), formatD(endTime)};
    }
}
